package com.qsw.qswcommonlib.util;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.util.SparseArray;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

/**
 * 资源相关工具
 */
public class CommonResUtil {

    private CommonResUtil() {
    }

    /**
     * 根据资源文件名获取资源文件ID
     *
     * @param context 环境
     * @param name    资源名称
     * @return 资源文件ID
     */
    public static int getResId(Context context, String name) {
        return context.getResources().getIdentifier(name, "drawable", context.getApplicationInfo().packageName);
    }

    /**
     * 获取字符串宽高，宽高都恰好包裹字符串
     *
     * @param text  要测试的字符串
     * @param paint 测试使用的画笔
     * @return 若字符串为空则返回null，否则返回Pair-width, height
     */
    public static Pair<Integer, Integer> getTextSize(String text, Paint paint) {
        if (TextUtils.isEmpty(text)) {
            return null;
        }
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return new Pair<>(rect.width(), rect.height());
    }

    /**
     * 获取字符串宽度，会比实际宽度稍大，使得绘制时和其它内容间有一定间距
     *
     * @param text  要测试的字符串
     * @param paint 测试使用的画笔
     * @return 字符串宽度
     */
    public static float getTextBigWidth(String text, Paint paint) {
        if (TextUtils.isEmpty(text)) {
            return 0;
        }
        return paint.measureText(text, 0, text.length());
    }

    /**
     * 获取屏幕可显示尺寸
     *
     * @param context 环境
     * @return 宽，高，为屏幕可显示区域，单位：像素
     */
    public static Pair<Integer, Integer> getScreenSize(Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return new Pair<>(displayMetrics.widthPixels, displayMetrics.heightPixels);
    }

    /**
     * 获取屏幕真实完整尺寸，包括系统占用尺寸
     *
     * @param activity 环境
     * @return 宽，高，屏幕真实完整尺寸，单位：像素
     */
    public static Pair<Integer, Integer> getRealScreenSize(Activity activity) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
        return new Pair<>(displayMetrics.widthPixels, displayMetrics.heightPixels);
    }

    /**
     * 底部虚拟按键栏的高度
     *
     * @return 底部虚拟按键栏的高度
     */
    public static int getSoftButtonsBarHeight(Activity activity) {
        DisplayMetrics metrics = new DisplayMetrics();
        // 这个方法获取可能不是真实屏幕的高度
        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int usableHeight = metrics.heightPixels;
        // 获取当前屏幕的真实高度
        activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
        int realHeight = metrics.heightPixels;
        if (realHeight > usableHeight) {
            return realHeight - usableHeight;
        } else {
            return 0;
        }
    }

    /**
     * dp转px
     *
     * @param context 环境
     * @param dpValue dp
     * @return px
     */
    public static int dp2px(Context context, float dpValue) {
        return (int) (dpValue * context.getResources().getDisplayMetrics().density + 0.5f);
    }

    /**
     * px转dp
     *
     * @param context 环境
     * @param pxValue px
     * @return dp
     */
    public static int px2dp(Context context, int pxValue) {
        return (int) ((pxValue - 0.5f) / context.getResources().getDisplayMetrics().density);
    }

    /**
     * sp转px
     *
     * @param context 环境
     * @param sp      sp
     * @return px
     */
    public static int sp2px(Context context, int sp) {
        return (int) (sp * context.getResources().getDisplayMetrics().scaledDensity + 0.5f);
    }

    /**
     * px转sp
     *
     * @param context 环境
     * @param pxValue px
     * @return sp
     */
    public static int px2sp(Context context, int pxValue) {
        return (int) ((pxValue - 0.5f) / context.getResources().getDisplayMetrics().scaledDensity);
    }

    /**
     * 获取应用程序名称
     *
     * @param context 环境
     * @return 应用程序名称
     */
    public static String getAppName(Context context) throws PackageManager.NameNotFoundException {
        PackageManager packageManager = context.getPackageManager();
        PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
        int nameRes = packageInfo.applicationInfo.labelRes;
        return context.getString(nameRes);
    }

    /**
     * 获取应用程序版本名称
     *
     * @param context 环境
     * @return 应用程序版本名称
     */
    public static String getAppVersionName(Context context) throws PackageManager.NameNotFoundException {
        PackageManager packageManager = context.getPackageManager();
        PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionName;
    }

    /**
     * 获取应用程序版本号
     *
     * @param context 环境
     * @return 应用程序版本号
     */
    public static int getAppVersionCode(Context context) throws PackageManager.NameNotFoundException {
        PackageManager packageManager = context.getPackageManager();
        PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionCode;
    }

    /**
     * 获取应用程序包名
     *
     * @param context 环境
     * @return 应用程序包名
     */
    public static String getAppPackageName(Context context) {
        return context.getPackageName();
    }

    /**
     * 获取应用程序图标
     *
     * @param context 环境
     * @return 应用程序图标
     */
    public static Bitmap getAppIcon(Context context) throws PackageManager.NameNotFoundException {
        PackageManager packageManager = context.getPackageManager();
        ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
        Drawable applicationIcon = packageManager.getApplicationIcon(applicationInfo);
        BitmapDrawable bitmapDrawable = (BitmapDrawable) applicationIcon;
        return bitmapDrawable.getBitmap();
    }

    /**
     * 获取应用签名Md5值
     *
     * @param context 环境
     * @return 应用签名Md5值
     */
    public static String getAppSignatureMd5Str(Context context) throws PackageManager.NameNotFoundException, NoSuchAlgorithmException {
        @SuppressLint("PackageManagerGetSignatures")
        PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
        Signature[] signs = packageInfo.signatures;
        Signature sign = signs[0];
        return CommonTransitionUtil.getMD5(sign.toByteArray());
    }

    /**
     * 获取CPU序列号，根据厂商定制不保证唯一
     *
     * @return CPU序列号
     */
    public static String getCPUSerial() throws IOException {
        String result = null;
        Process process = Runtime.getRuntime().exec("cat /proc/cpuinfo");
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = br.readLine()) != null) {
            String info = line.trim();
            // 对获取的每行的设备信息进行过滤，获得自己想要的。
            if (info.startsWith("Serial") && info.contains(":")) {
                String[] split = info.split(":");
                result = split[1].substring(1);
            }
        }
        return result;
    }

    /**
     * 获取SIM卡ICCID，需要权限
     * {@link android.Manifest.permission#READ_PHONE_STATE}
     * {@link android.Manifest.permission#READ_SMS}
     *
     * @return SIM卡ICCID
     */
    @SuppressLint("MissingPermission")
    public static String getICCID(Context context) {
        String iccid = "";
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
            SubscriptionManager sm = SubscriptionManager.from(context);
            List<SubscriptionInfo> sis = sm.getActiveSubscriptionInfoList();
            if (sis.size() > 0) {
                SubscriptionInfo si = sis.get(0);
                iccid = si.getIccId();
            }
        } else {
            //获取sim卡信息
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            // @SuppressLint("MissingPermission") String deviceid = tm.getDeviceId();
            String tel = tm.getLine1Number();
            iccid = tm.getSimSerialNumber();
            String imsi = tm.getSubscriberId();
            int simState = tm.getSimState();
        }
        return iccid;
    }

    /**
     * 复制普通文本到剪切板
     *
     * @param context 环境
     * @param str     要放进剪切板的文本
     */
    public static void copyToClipboard(Context context, String str) {
        ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        ClipData clipData = ClipData.newPlainText("Label", str);
        clipboardManager.setPrimaryClip(clipData);
    }

    /**
     * 获得一个指定的实线边框矩形Drawable
     *
     * @param strokeColor 描边色
     * @param strokeWidth 描边线宽度，单位：pixels
     * @param radius      圆角角度，单位：pixels
     * @return GradientDrawable
     */
    public static Drawable getShapeDrawable(int strokeColor, int strokeWidth, float radius) {
        return getShapeDrawable(ColorStateList.valueOf(Color.TRANSPARENT),
                ColorStateList.valueOf(strokeColor), strokeWidth, 0, 0,
                radius);
    }

    /**
     * 获得一个指定的虚线矩形Drawable
     *
     * @param strokeColor 描边色
     * @param strokeWidth 描边线宽度，单位：pixels
     * @param dashWidth   虚线宽度，单位：pixels
     * @param dashGap     虚线间距，当dashGap=0dp时，为实线，单位：pixels
     * @param radius      圆角角度，单位：pixels
     * @return GradientDrawable
     */
    public static Drawable getShapeDrawable(int strokeColor, int strokeWidth, float dashWidth, float dashGap, float radius) {
        return getShapeDrawable(ColorStateList.valueOf(Color.TRANSPARENT),
                ColorStateList.valueOf(strokeColor), strokeWidth, dashWidth, dashGap,
                radius);
    }

    /**
     * 获得一个指定的矩形Drawable
     *
     * @param solidColor  填充色
     * @param strokeColor 描边色
     * @param strokeWidth 描边线宽度，单位：pixels
     * @param dashWidth   虚线宽度，单位：pixels
     * @param dashGap     虚线间距，当dashGap=0dp时，为实线，单位：pixels
     * @param radius      圆角角度，单位：pixels
     * @return GradientDrawable
     */
    public static Drawable getShapeDrawable(int solidColor,
                                            int strokeColor, int strokeWidth,
                                            float dashWidth, float dashGap,
                                            float radius) {
        return getShapeDrawable(ColorStateList.valueOf(solidColor),
                ColorStateList.valueOf(strokeColor), strokeWidth, dashWidth, dashGap,
                radius);
    }

    /**
     * 获得一个指定的矩形Drawable
     *
     * @param solidColors  填充色
     * @param strokeColors 描边色
     * @param strokeWidth  描边线宽度，单位：pixels
     * @param dashWidth    虚线宽度，单位：pixels
     * @param dashGap      虚线间距，当dashGap=0时，为实线，单位：pixels
     * @param radius       圆角角度，单位：pixels
     * @return GradientDrawable
     */
    public static Drawable getShapeDrawable(ColorStateList solidColors,
                                            ColorStateList strokeColors, int strokeWidth,
                                            float dashWidth, float dashGap,
                                            float radius) {
        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setShape(GradientDrawable.RECTANGLE);
        gradientDrawable.setCornerRadius(radius);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            gradientDrawable.setColor(solidColors);
            // 显示一条虚线，线宽为dashWith，虚线之间的空隙宽度为dashGap，当dashGap=0时，为实线
            gradientDrawable.setStroke(strokeWidth, strokeColors, dashWidth, dashGap);
        } else {
            gradientDrawable.setColor(solidColors.getDefaultColor());
            // 显示一条虚线，线宽为dashWith，虚线之间的空隙宽度为dashGap，当dashGap=0时，为实线
            gradientDrawable.setStroke(strokeWidth, strokeColors.getDefaultColor(), dashWidth, dashGap);
        }
        return gradientDrawable;
    }

    /**
     * 获取图形选择器
     *
     * @param checkedDrawable 选中时的图形
     * @param normalDrawable  未选中时的图形
     * @return 图形选择器
     */
    public static StateListDrawable getDrawableSelector(Drawable checkedDrawable, Drawable normalDrawable) {
        StateListDrawable drawable = new StateListDrawable();
        drawable.addState(new int[]{android.R.attr.state_checked}, checkedDrawable);
        drawable.addState(new int[]{-android.R.attr.state_checked}, normalDrawable);
        return drawable;
    }

    /**
     * 获取颜色选择器
     *
     * @param checkedColor 选中时的颜色
     * @param normalColor  未选中时的颜色
     * @return 颜色选择器
     */
    public static ColorStateList getColorSelector(int checkedColor, int normalColor) {
        int[][] states = new int[][]{
                new int[]{android.R.attr.state_checked},
                new int[]{-android.R.attr.state_checked}
        };
        int[] colors = new int[]{checkedColor, normalColor};
        return new ColorStateList(states, colors);
    }

    /**
     * 清空APP信息
     *
     * @param packageName 包名
     * @return
     * @throws IOException
     */
    public static Process clearAppUserData(String packageName) throws IOException {
        return execRuntimeProcess("pm clear " + packageName);
    }

    /**
     * 执行命令
     *
     * @param commond 命令
     * @return 执行结果
     * @throws IOException 错误
     */
    private static Process execRuntimeProcess(String commond) throws IOException {
        return Runtime.getRuntime().exec(commond);
    }

    /**
     * 快速点击的判定时间，两次点击间隔小于该时间判定为快速点击
     */
    private static final int INTERVAL_FAST_TIME = 500;
    /**
     * 存放控件上次点击时间
     */
    private static final SparseArray<Long> mLastClickTimestampMap = new SparseArray<>();

    /**
     * 判定是否为快速点击
     *
     * @param viewId 要判断的控件ID
     * @return true：是快速点击；false：不是快速点击
     */
    public static boolean isFastClick(int viewId) {
        Long lastClickTimestamp = mLastClickTimestampMap.get(viewId);
        mLastClickTimestampMap.put(viewId, System.currentTimeMillis());
        if (lastClickTimestamp == null) {
            return false;
        }
        return System.currentTimeMillis() - lastClickTimestamp < INTERVAL_FAST_TIME;
    }

    /**
     * 检查网络是否可用，需要权限{@link android.Manifest.permission#ACCESS_NETWORK_STATE}
     *
     * @param context 环境
     * @return true：可用；false：不可用
     */
    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager != null) {
            @SuppressLint("MissingPermission") NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            return activeNetworkInfo != null && activeNetworkInfo.isConnected();
        }
        return false;
    }

    /**
     * 获取当前CPU频率（不知道是否准确）
     *
     * @return 当前CPU频率
     * @throws IOException 获取异常
     */
    public static List<String> getCPUFrequency() throws IOException {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            Process process = Runtime.getRuntime().exec("cat /sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_freq");
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = br.readLine()) != null) {
                String info = line.trim();
                if (!TextUtils.isEmpty(info)) {
                    result.add(info);
                }
            }
        }
        return result;
    }

    /**
     * 获取系统开机时间，单位：秒
     *
     * @return 系统开机时间，单位：秒
     * @throws IOException 获取异常
     */
    public static long getSystemBootTime() throws IOException {
        long bootTime = 0;
        for (int i = 0; i < 4; i++) {
            Process process = Runtime.getRuntime().exec("cat /proc/stat");
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = br.readLine()) != null) {
                String info = line.trim();
                if (!TextUtils.isEmpty(info) && info.startsWith("btime")) {
                    String[] split = info.split(" ");
                    if (split.length > 1) {
                        try {
                            bootTime = Long.parseLong(split[1]);
                        } catch (NumberFormatException e) {
                            bootTime = 0;
                        }
                    }
                    break;
                }
            }
        }
        return bootTime;
    }
}
